﻿using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Xml.Serialization;
using Microsoft.Xna.Framework.Content;

namespace Gamev1
{
    public class Character : Sprite
    {
        #region CharacterState enum
        public enum CharacterState
        {
            On_Ground,
            Jumping
        }
        #endregion

        #region Fields
        private string _naam;
        private KeyboardState prevKeyState;
        public CharacterState currentCharacterState;
        private float jumpHeight = -16f;
        public float speed = 5f;
        public Weapon weapon;
        private int _direction;
        private double bonusDuration = 5.0;
        private double elapsedBonusTime;
        [XmlIgnore]
        public bool hasBonus;
        public bool hasKey = false;
        public string[] animationWalkPath;
        public string[] animationJumpPath;
        private Animation animationWalk;
        private Animation animationJump;
        private bool isJumping;
        public int monstersKilled;
        [XmlIgnore]
        public int Score { get; private set; }
        #endregion

        public Character()
        {
            currentCharacterState = CharacterState.Jumping;
            Health = 250;
            Score = 1000;
            monstersKilled = 0;
            TimeLimit = 1000;
        }

        #region Update & draw
        public override void update(GameTime gameTime)
        {
            updateAnimations(gameTime);
            handleInput(gameTime);
            checkGravity();
            Velocity += Acceleration;
            Position += Velocity;
            checkBounds();
            checkBonusTime(gameTime);
            calculateScore();
            CurrentTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
        }

        public override void draw(SpriteBatch spriteBatch)
        {
            drawAnimations(spriteBatch);
        }

        private void drawAnimations(SpriteBatch spriteBatch)
        {
            if (currentCharacterState == CharacterState.On_Ground)
            {
                animationWalk.Draw(spriteBatch, this);
            }
            else if (currentCharacterState == CharacterState.Jumping)
            {
                animationJump.Draw(spriteBatch, this);
            }
        }

        private void updateAnimations(GameTime gameTime)
        {
            if (currentCharacterState == CharacterState.Jumping)
            {
                animationJump.Update(gameTime, _direction);
            }
            else if (currentCharacterState == CharacterState.On_Ground)
            {
                animationWalk.Update(gameTime, _direction);
            }
        }

        #endregion

        #region Controls
        public void handleInput(GameTime gameTime)
        {
            KeyboardState keyState = Keyboard.GetState();
            if (keyState.IsKeyDown(Keys.A))
            {
                moveLeft();
            }
            else if (keyState.IsKeyDown(Keys.D))
            {
                moveRight();
            }
            else
            {
                Velocity = new Vector2(0, Velocity.Y);
                animationWalk.Frames = 0;
            }
            if (keyState.IsKeyDown(Keys.W) && prevKeyState.IsKeyUp(Keys.W) && currentCharacterState != CharacterState.Jumping)
            {
                jump();
            }

            if (keyState.IsKeyDown(Keys.Space) && prevKeyState.IsKeyUp(Keys.Space))
            {
                if (weapon != null)
                {
                    CanShoot = true;
                }
            }

            prevKeyState = keyState;
        }

        public void jump()
        {

            if (!isJumping)
            {
                Velocity = new Vector2(Velocity.X, jumpHeight);
                isJumping = true;
                currentCharacterState = CharacterState.Jumping;
            }
        }

        public void moveLeft()
        {
            Velocity = new Vector2(-speed, Velocity.Y);
            _direction = (int)Direction.Left;
        }

        public void moveRight()
        {
            Velocity = new Vector2(speed, Velocity.Y);
            _direction = (int)Direction.Right;
        }

        public Bullet shoot(ContentManager content)
        {
            return weapon.Shoot(content);
        }

        #endregion

        #region Collision
        public override void collisionWith(Sprite sprite)
        {
            if (sprite is Platform)
            {
                Platform platform = (Platform)sprite;
                collisionCharacterPlatform(platform);
            }
        }

        private void collisionCharacterPlatform(Platform platform)
        {
            if (platform.isTouchingTop)
            {
                currentCharacterState = CharacterState.On_Ground;
                isJumping = false;
            }
            else
            {
                currentCharacterState = CharacterState.Jumping;
            }
        }
        #endregion

        #region Methods
        public void calculateScore()
        {
            Score = (int)((TimeLimit - CurrentTime) * 15) + (Health * 5) + monstersKilled * 1000;
        }

        public void checkGravity()
        {
            if (currentCharacterState == CharacterState.Jumping)
            {
                Gravity = 0.65f;
                applyGravity(Gravity);
                isJumping = false;
            }
            else if (currentCharacterState == CharacterState.On_Ground)
            {
                Gravity = 0f;
                applyGravity(Gravity);
            }
        }

        public void applyGravity(float gravity)
        {
            Acceleration = new Vector2(0f, gravity);
        }

        public void checkBounds()
        {
            if (atLeftEdge())
            {
                Position = new Vector2(10, Position.Y);
            }
            else if (atRightEdge())
            {
                Position = new Vector2(Game1.screenWidth - Rectangle.Width - 10, Position.Y);
            }
            if (atBottomEdge())
            {
                currentCharacterState = CharacterState.On_Ground;
                Position = new Vector2(Position.X, Game1.screenHeight - 130);
                isJumping = false;
            }
        }

        public bool atLeftEdge()
        {
            return Position.X < 10;
        }

        public bool atRightEdge()
        {
            return Position.X > Game1.screenWidth - Rectangle.Width - 10;
        }

        public bool atBottomEdge()
        {
            return Position.Y > Game1.screenHeight - 130;
        }


        public void pickWeapon(Weapon weapon)
        {
            this.weapon = weapon;
        }

        public override void loadContent(ContentManager content)
        {
            float animationDelay = 250f;
            animationWalk = new Animation(animationDelay);
            animationWalk.initializeTextures(content, animationWalkPath);
            Texture = animationWalk.AnimationTextures[0];
            animationJump = new Animation(animationDelay);
            animationJump.initializeTextures(content, animationJumpPath);
        }

        public void checkBonusTime(GameTime gameTime)
        {
            if (hasBonus)
            {
                elapsedBonusTime += (double)gameTime.ElapsedGameTime.TotalSeconds;
                if (elapsedBonusTime > bonusDuration && hasBonus)
                {
                    JumpHeight = -16f;
                    hasBonus = false;
                    elapsedBonusTime = 0.0;
                }
            }
        }

        public string[] characterAnimationPath(int arrayLength, string path)
        {
            string[] texturePath = new string[arrayLength];

            for (int index = 0; index < arrayLength; index++)
            {
                int plaatjeNummer = index + 1;
                texturePath[index] = path + plaatjeNummer;
            }

            return texturePath;
        }
        #endregion

        #region Getters & setters

        [XmlIgnore]
        public int TimeLimit { get; set; }

        public float Gravity { get; set; }

        [XmlIgnore]
        public float CurrentTime { get; set; }

        [XmlIgnore]
        public int Health { get; set; }

        [XmlIgnore]
        public double BonusTime
        {
            get { return elapsedBonusTime; }
        }

        [XmlIgnore]
        public Vector2 Velocity { get; set; }

        public bool IsAlive
        {
            get
            {
                if (Health <= 0)
                {
                    return false;
                }
                return true;
            }
        }

        [XmlIgnore]
        public bool CanShoot { get; set; }

        [XmlIgnore]
        public float JumpHeight
        {
            get { return jumpHeight; }
            set { jumpHeight = value; }
        }

        [XmlIgnore]
        public Vector2 Acceleration { get; set; }

        [XmlIgnore]
        public Animation CharacterAnimation
        {
            get { return animationWalk; }
            set { animationWalk = value; }
        }

        [XmlIgnore]
        public int CurrentDirection
        {
            get { return _direction; }
            set { _direction = value; }
        }
        #endregion
    }
}
